#include "Sock.hpp"
#include <string>
#include <pthread.h>
#include "protol.hpp"
#include <mutex>
#include <cstdlib>
#include <cstring>


const int defaultport = 8888;
const std::string defaultip = "0.0.0.0";

class Server;

class ThreadData
{
public:
    ThreadData(int fd, const std::string &ip, const uint16_t &p, Server *t) : sockfd(fd), clientip(ip), clientport(p), tsvr(t)
    {
    }

public:
    int sockfd;
    std::string clientip;
    uint16_t clientport;
    Server *tsvr;
};

class Server
{
public:
    Server(int port = defaultport, std::string ip = defaultip)
        : _sock(Sock::Sock(port, ip))
    {
        _sock.InitSev();
        _mutex = new std::mutex;
    }

    static void *Routine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->tsvr->Service(td->sockfd, td->clientip, td->clientport);
        delete td;
        return nullptr;
    }

    void Start()
    {
        while (true)
        {
            std::string clientip;
            int clientport;
            int connfd = _sock.Accept(clientip, clientport);
            _mutex->lock();
            _protol.AddUser(connfd, clientport, clientip);
            _mutex->unlock();
            if (connfd < 0)
            {
                std::cout << "accept error" << std::endl;
            }
            else
            {
                std::cout << "accept success" << std::endl;
                for (auto i : _protol.get_userlist())
                {
                    if (i.first != connfd)
                        write(i.first, _protol.get_uselistid().c_str(), _protol.get_uselistid().size());
                }
            }
            ThreadData *td = new ThreadData(connfd, clientip, clientport, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, Routine, td);
        }
    }

    void Service(int sockfd, const std::string &clientip, const uint16_t &clientport)
    {
        // 测试代码
        char buffer[4096];
        std::string ss = "now have: \n";
        ss += _protol.get_uselistid();
        write(sockfd, ss.c_str(), ss.size());

        while (true)
        {
            int ret = read(sockfd, buffer, sizeof(buffer));
            if (ret < 0)
            {
                std::cout << "read error" << std::endl;
            }
            else if (ret == 0)
            {
                std::cout << "client quit" << std::endl;
                _mutex->lock();
                _protol.DelUser(sockfd);
                _mutex->unlock();
                break;
            }
            else
            {
                buffer[ret] = '\0';
                std::string msg;
                for (auto i : buffer)
                {
                    if (i != '\0')
                    {
                        msg += i;
                    }
                }
                // 1.process add friend
                if (_protol.judge_addfrend(buffer))
                {
                    int afid = buffer[1] - '0';
                    std::string msg2 = _protol.selizer_addfriend(sockfd);
                    write(afid, msg2.c_str(), msg2.size());
                }else if (_protol.judge_agreefrend(buffer))//2.proscess agree friend
                {
                    int afid = buffer[1] - '0';
                    std::string msg2 = _protol.selizer_agreefriend(sockfd);
                    write(afid, msg2.c_str(), msg2.size());
                }
                else
                {
                    buffer[ret] = '\0';
                    // process friend chat;
                    std::string msg_body;
                    int id;
                    _protol.Deselizer(msg, id, msg_body);
                    if (_protol.find(id))
                    {
                        msg_body += "\n";
                        std::string sendmsg = "user " + std::to_string(id) + " say: " + msg_body;
                        write(id, sendmsg.c_str(), sendmsg.size());
                    }
                    else
                    {
                        std::string sendmsg = "user not found!";
                        write(sockfd, sendmsg.c_str(), sendmsg.size());
                    }
                }
                //memset(buffer, 0, sizeof(buffer));
                // debug
                buffer[ret] = '\0';
                //std::cout << "recv: " << buffer << std::endl;
            }
        }
    }
    ~Server()
    {
        delete _mutex;
    }

private:
    Sock::Sock _sock;
    ProtoL _protol;
    std::mutex *_mutex;
};

int main()
{
    Server server;
    server.Start();
    return 0;
}